import * as THREE from "three";
import { Shape, ShapeParams, EmissionType } from "./Shape";

/**
 * 支持 BufferGeometry 的发射形状
 * 可以从顶点、面或体积中发射粒子
 */
export class BufferGeometryShape extends Shape {
    private positionAttribute?: THREE.BufferAttribute;
    private normalAttribute?: THREE.BufferAttribute;
    private indexAttribute?: THREE.BufferAttribute | null;

    constructor(origin: THREE.Vector3, params: ShapeParams = {}, geometry?: THREE.BufferGeometry) {
        super(origin, params, geometry);
        this.updateGeometryData();
    }

    private updateGeometryData() {
        if (!this.geometry) return;
        
        this.positionAttribute = this.geometry.getAttribute('position') as THREE.BufferAttribute;
        this.normalAttribute = this.geometry.getAttribute('normal') as THREE.BufferAttribute;
        this.indexAttribute = this.geometry.getIndex();
    }

    setGeometry(geometry: THREE.BufferGeometry) {
        super.setGeometry(geometry);
        this.updateGeometryData();
    }

    getRandomPosition(): THREE.Vector3 {
        if (!this.positionAttribute) {
            return this.origin.clone();
        }

        switch (this.emissionType) {
            case EmissionType.VERTICES:
                return this.getRandomVertexPosition();
            case EmissionType.SURFACE:
                return this.getRandomSurfacePosition();
            case EmissionType.VOLUME:
                return this.getRandomVolumePosition();
            default:
                return this.getRandomVertexPosition();
        }
    }

    getRandomNormal(): THREE.Vector3 {
        if (!this.normalAttribute) {
            return new THREE.Vector3(0, 1, 0); // 默认法向
        }

        switch (this.emissionType) {
            case EmissionType.VERTICES:
                return this.getRandomVertexNormal();
            case EmissionType.SURFACE:
                return this.getRandomSurfaceNormal();
            default:
                return this.getRandomVertexNormal();
        }
    }

    getNormalAtPosition(position: THREE.Vector3): THREE.Vector3 {
        // 这里可以实现基于位置的法向量插值计算
        // 目前简化为返回随机法向
        return this.getRandomNormal();
    }

    private getRandomVertexPosition(): THREE.Vector3 {
        const vertexCount = this.positionAttribute!.count;
        const randomIndex = Math.floor(Math.random() * vertexCount);
        
        const x = this.positionAttribute!.getX(randomIndex);
        const y = this.positionAttribute!.getY(randomIndex);
        const z = this.positionAttribute!.getZ(randomIndex);
        
        return new THREE.Vector3(x, y, z).add(this.origin);
    }

    private getRandomVertexNormal(): THREE.Vector3 {
        if (!this.normalAttribute) {
            return new THREE.Vector3(0, 1, 0);
        }

        const vertexCount = this.normalAttribute.count;
        const randomIndex = Math.floor(Math.random() * vertexCount);
        
        const x = this.normalAttribute.getX(randomIndex);
        const y = this.normalAttribute.getY(randomIndex);
        const z = this.normalAttribute.getZ(randomIndex);
        
        return new THREE.Vector3(x, y, z).normalize();
    }

    private getRandomSurfacePosition(): THREE.Vector3 {
        if (!this.indexAttribute) {
            // 如果没有索引，回退到顶点模式
            return this.getRandomVertexPosition();
        }

        // 随机选择一个三角面
        const faceCount = this.indexAttribute.count / 3;
        const randomFaceIndex = Math.floor(Math.random() * faceCount);
        
        // 获取三角面的三个顶点索引
        const i0 = this.indexAttribute.getX(randomFaceIndex * 3);
        const i1 = this.indexAttribute.getX(randomFaceIndex * 3 + 1);
        const i2 = this.indexAttribute.getX(randomFaceIndex * 3 + 2);
        
        // 获取三个顶点位置
        const v0 = new THREE.Vector3(
            this.positionAttribute!.getX(i0),
            this.positionAttribute!.getY(i0),
            this.positionAttribute!.getZ(i0)
        );
        const v1 = new THREE.Vector3(
            this.positionAttribute!.getX(i1),
            this.positionAttribute!.getY(i1),
            this.positionAttribute!.getZ(i1)
        );
        const v2 = new THREE.Vector3(
            this.positionAttribute!.getX(i2),
            this.positionAttribute!.getY(i2),
            this.positionAttribute!.getZ(i2)
        );
        
        // 在三角面内随机采样
        const u = Math.random();
        const v = Math.random();
        
        // 确保在三角形内
        if (u + v > 1) {
            return v0.clone()
                .multiplyScalar(1 - u - v)
                .add(v1.clone().multiplyScalar(u))
                .add(v2.clone().multiplyScalar(v))
                .add(this.origin);
        } else {
            return v0.clone()
                .multiplyScalar(1 - u - v)
                .add(v1.clone().multiplyScalar(u))
                .add(v2.clone().multiplyScalar(v))
                .add(this.origin);
        }
    }

    private getRandomSurfaceNormal(): THREE.Vector3 {
        if (!this.indexAttribute) {
            return this.getRandomVertexNormal();
        }

        // 随机选择一个三角面并计算其法向量
        const faceCount = this.indexAttribute.count / 3;
        const randomFaceIndex = Math.floor(Math.random() * faceCount);
        
        const i0 = this.indexAttribute.getX(randomFaceIndex * 3);
        const i1 = this.indexAttribute.getX(randomFaceIndex * 3 + 1);
        const i2 = this.indexAttribute.getX(randomFaceIndex * 3 + 2);
        
        // 如果有法向量属性，则插值计算
        if (this.normalAttribute) {
            const n0 = new THREE.Vector3(
                this.normalAttribute.getX(i0),
                this.normalAttribute.getY(i0),
                this.normalAttribute.getZ(i0)
            );
            const n1 = new THREE.Vector3(
                this.normalAttribute.getX(i1),
                this.normalAttribute.getY(i1),
                this.normalAttribute.getZ(i1)
            );
            const n2 = new THREE.Vector3(
                this.normalAttribute.getX(i2),
                this.normalAttribute.getY(i2),
                this.normalAttribute.getZ(i2)
            );
            
            // 简化：返回三个法向量的平均值
            return n0.add(n1).add(n2).divideScalar(3).normalize();
        } else {
            // 计算面法向量
            const v0 = new THREE.Vector3(
                this.positionAttribute!.getX(i0),
                this.positionAttribute!.getY(i0),
                this.positionAttribute!.getZ(i0)
            );
            const v1 = new THREE.Vector3(
                this.positionAttribute!.getX(i1),
                this.positionAttribute!.getY(i1),
                this.positionAttribute!.getZ(i1)
            );
            const v2 = new THREE.Vector3(
                this.positionAttribute!.getX(i2),
                this.positionAttribute!.getY(i2),
                this.positionAttribute!.getZ(i2)
            );
            
            const edge1 = v1.clone().sub(v0);
            const edge2 = v2.clone().sub(v0);
            
            return edge1.cross(edge2).normalize();
        }
    }

    private getRandomVolumePosition(): THREE.Vector3 {
        // 对于体积发射，我们需要计算几何体的包围盒并在其内部随机采样
        if (!this.geometry) {
            return this.origin.clone();
        }

        this.geometry.computeBoundingBox();
        const box = this.geometry.boundingBox!;
        
        // 在包围盒内随机采样
        const x = Math.random() * (box.max.x - box.min.x) + box.min.x;
        const y = Math.random() * (box.max.y - box.min.y) + box.min.y;
        const z = Math.random() * (box.max.z - box.min.z) + box.min.z;
        
        return new THREE.Vector3(x, y, z).add(this.origin);
    }
}